/**
 * Create by CaoWenjian
 *
 * @copyRight: 2018
 **/
package com.bjboot.caocao.system.adpect;

import com.bjboot.caocao.common.utils.HttpContextUtils;
import com.bjboot.caocao.common.utils.IPUtils;
import com.bjboot.caocao.common.utils.JSONUtils;
import com.bjboot.caocao.system.annotation.BJLog;
import com.bjboot.caocao.system.dao.LogMapper;
import com.bjboot.caocao.system.domain.LogDO;
import com.bjboot.caocao.system.domain.UserDO;
import com.bjboot.caocao.system.shiro.ShiroUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.Date;

/**
 *@Description 记录系统日志的aspect
 *@Author 操文健
 *@Date 2018-09-06 下午7:36
 *@Version 1.0
 **/
@Aspect
@Component
public class SysLogRecodeAspect {
    private static final Logger logger = LoggerFactory.getLogger(SysLogRecodeAspect.class);

    @Autowired
    private LogMapper logMapper;
    /**
     * 自定义切入点
     * 针对含有BJLog注解的方法进行AOP
     */
    @Pointcut("@annotation(com.bjboot.caocao.system.annotation.BJLog)")
    public void logPointCut() {
    }

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        // 执行方法
        Object result = point.proceed();
        // 执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;
        //异步保存日志
        saveLog(point, time);
        return result;
    }

    /**
     * 根据切面的信息，将访问方法的日志插入到系统当中
     * @param point
     * @param time
     */
    private void saveLog(ProceedingJoinPoint point, long time) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        // 创建一个系统sysLog的domain
        LogDO logDO = new LogDO();
        // 设置用户的相关信息
        UserDO curUser = ShiroUtils.getUser();
        if (StringUtils.isEmpty(curUser)) {
            // 如果当前访问的方法名称不为空，则进行将对应的方法名称插入
            if (StringUtils.isEmpty(signature.getName())) {
                logDO.setUserId(-1L);
                logDO.setUsername(signature.getName());
            } else {
                logDO.setUserId(-1L);
                logDO.setUsername("获取用户名称为空");
            }
        } else {
            logDO.setUserId(curUser.getUserId());
            logDO.setUsername(curUser.getUsername());
        }
        // 获取当前界面的操作描述
        BJLog bjLog = method.getAnnotation(BJLog.class);
        if (!StringUtils.isEmpty(bjLog)) {
            // 设置操作
            logDO.setOperation(bjLog.value());
        }
        // 设置当前访问该point的耗时,相应时间
        logDO.setTime((int) time);
        // 请求方法
        String className = point.getTarget().getClass().getName();
        String methodName = signature.getName();
        logDO.setMethod(className + "." + methodName + "()");
        // 请求参数
        Object[] args = point.getArgs();
        try {
            String params = JSONUtils.beanToJson(args[0]);
            if (params.length() > 4999) {
                params = params.substring(0, 4999);
            }
            logDO.setParams(params);
        } catch (Exception e) {
            logger.error("JSONUtils转换对象出现异常", e);
        }
        // 请求的IP地址
        logDO.setIp(IPUtils.getIpAddr(HttpContextUtils.getHttpServletRequest()));
        // 设置当前插入时间
        logDO.setGmtCreate(new Date());
        logger.debug(logDO.toString());
        logMapper.insert(logDO);
    }
}
